﻿using System;
using System.IO;
using System.IO.Packaging;
using System.Net;
using System.Threading;
using BluePortal.Medias.Core;

namespace BluePortal.Encoding.Core.Providers

{
    /// <summary>
    /// SilverLightUrl=https://silverlight.services.live.com/;AccountID=<>;AccountID=<>
    /// </summary>
    public class SilverLightUploadService : BaseUploadService, IVideoUploadService
    {
        protected string silverLightUrl { get { return ConnectionParameters["SilverLightUrl"]; } }
        protected string ApplicationName = null;
        protected BCVideo bc = new BCVideo();

        string AccountKey { get { return ConnectionParameters["AccountKey"]; } }
        string AccountID { get { return ConnectionParameters["AccountID"]; } }

        #region private methods

        /// <summary>
        /// concat all url, and add "/" if needed
        /// </summary>
        /// <param name="rooturl"></param>
        /// <param name="urls"></param>
        /// <returns></returns>
        private static string Concat(string acctUrl, string subUrl, string query)
        {
            string text = acctUrl;
            if (subUrl != null)
            {
                text = text + "/" + subUrl;
            }
            if (query != null)
            {
                text = text + query;
            }
            return text;
        }

        /// <summary>
        /// Create request to upload with an specific account 
        /// </summary>
        /// <param name="acctUrl"></param>
        /// <param name="subUrl"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        protected WebRequest CreateRequest(string subUrl, string query, string accountID, string accountKey)
        {
            return CreateRequest(subUrl, query, accountID, accountKey, 0x927c0);
        }
        private WebRequest CreateRequest(string subUrl, string query, string accountID, string accountKey, int timeout)
        {
            WebRequest request = WebRequest.Create(silverLightUrl + Concat(accountID, subUrl, query));
            byte[] inArray = System.Text.Encoding.Default.GetBytes(accountID + ":" + accountKey);
            string text2 = "Basic " + Convert.ToBase64String(inArray);
            request.Headers["Authorization"] = text2;
            request.Credentials = new NetworkCredential(accountID, accountKey);
            request.Timeout = timeout;
            return request;
        }

        protected bool InternalUpload(string subUrl, string localFile, string accountID, string accountKey, Guid vid)
        {   
            FileInfo info = new FileInfo(localFile);
            Stream inputStream = null;
            Stream output = null;
            try
            {
                WebRequest state = this.CreateRequest(subUrl, null, accountID, accountKey, 0x186a0);
                state.Method = "POST";
                state.ContentType = "application/zip";
                inputStream = new FileStream(localFile, FileMode.Open);
                AsyncCallback callback = null;
                using (AutoResetEvent requestAr = new AutoResetEvent(false))
                {
                    if (callback == null)
                    {
                        callback = delegate(IAsyncResult res)
                        {
                            output = ((WebRequest)res.AsyncState).EndGetRequestStream(res);
                            requestAr.Set();
                        };
                    }
                    IAsyncResult result = state.BeginGetRequestStream(callback, state);
                    if (requestAr.WaitOne(5000, true) && result.IsCompleted)
                    {
                        try
                        {
                            Utils.CopyStream(inputStream, output, 0x2000);
                        }
                        finally
                        {
                            output.Close();
                            output = null;
                        }
                        IAsyncResult result2 = state.BeginGetResponse(delegate(IAsyncResult _result)
                            {
                                WebRequest asyncState = (WebRequest)_result.AsyncState;
                                HttpWebResponse response = (HttpWebResponse)asyncState.EndGetResponse(_result);
                                if (response.StatusCode != HttpStatusCode.OK)
                                {
                                    throw new Exception("response.StatusCode : " + response.StatusCode);
                                }
                            }, state);
                        while (true)
                        {
                            if (result2.AsyncWaitHandle.WaitOne(250, true))
                            {
                                break;
                            }
                        }
                    }
                    else 
                    {
                        throw new Exception("Server unavailable");
                    }

                    Thread.Sleep(5000);
                    // verify the getURL
                    ApplicationName = vid.ToString().Replace('-', '_');
                    WebRequest request = WebRequest.Create("http://silverlight.services.live.com/invoke/" + accountID + "/" + ApplicationName + "/start.js?id=bl2&u=" + DateTime.Now.Ticks);
                    WebResponse resp = (WebResponse)request.GetResponse();
                    Stream strm = resp.GetResponseStream();
                    StreamReader rdr = new StreamReader(strm);
                    string xmlResponse = rdr.ReadToEnd();
                    xmlResponse = xmlResponse.Substring(xmlResponse.IndexOf("http://"));
                    xmlResponse = xmlResponse.Substring(0, xmlResponse.IndexOf("\""));
                    if (xmlResponse == null)
                        throw new Exception("ExtractSilverlightStreamingUrl error");

                }
                return false;
            }
            finally
            {
                if (inputStream != null)
                {
                    inputStream.Close();
                }
                if (output != null)
                {
                    output.Close();
                }
            }
        }

        private void AddToZip(Package zip, string localFileName)
        {
            //Gets only filename, its will be the name in zip file
            string destFilename = ".\\" + Path.GetFileName(localFileName);
            Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
            PackagePart part = zip.CreatePart(uri, "");
            // Copy the data to the Document Part
            using (FileStream fileStream = new FileStream(localFileName, FileMode.Open, FileAccess.Read))
            {
                using (Stream dest = part.GetStream())
                {
                    Utils.CopyStream(fileStream, dest);
                }
            }
        }

        protected string ZipDir(string directory)
        {
            string zipFilename = Path.Combine(directory, "directory.zip");
            //deletes tmp file
            if (File.Exists(zipFilename))
                File.Delete(zipFilename);
            using (Package zip = System.IO.Packaging.Package.Open(zipFilename, FileMode.Create))
            {
                //add file to zip package
                foreach (string file in GetFiles(directory))
                {
                    AddToZip(zip, file);
                }
                //Adds silverlight manifest file
                AddToZip(zip, Utils.GetConfigFile("manifest.xml"));
            }
            return zipFilename;
        }

        #endregion

        #region IVideoUploadService Members

        public virtual void Upload(Video video, string directory)
        {
            string zipfilename = null;
            try
            {
                ApplicationName = video.ID.ToString().Replace('-', '_');
                zipfilename = ZipDir(directory);
                InternalUpload(ApplicationName, zipfilename, this.AccountID, this.AccountKey, video.ID);
                video.ProviderOptions = this.AccountID;
            }
            finally
            {
            }
        }

        public override string GetUrlFromVID(Guid vid)
        {
            //@todo
            //base.GetUrlFromVID(vid);

            string xmlResponse = ExtractSilverlightStreamingUrl(vid);
            return xmlResponse + "/" + vid + ".wmv";
        }

        private string ExtractSilverlightStreamingUrl(Guid vid)
        {
            Video v = bc.FindVideoByID(vid);
            ApplicationName = vid.ToString().Replace('-', '_');

            WebRequest request = WebRequest.Create("http://silverlight.services.live.com/invoke/" + v.ProviderOptions + "/" + ApplicationName + "/start.js?id=bl2&u=" + DateTime.Now.Ticks);
            WebResponse resp = (WebResponse)request.GetResponse();
            Stream strm = resp.GetResponseStream();
            StreamReader rdr = new StreamReader(strm);
            string xmlResponse = rdr.ReadToEnd();
            xmlResponse = xmlResponse.Substring(xmlResponse.IndexOf("http://"));
            xmlResponse = xmlResponse.Substring(0, xmlResponse.IndexOf("\""));
            return xmlResponse;
        }
        public override string GetUrlFromVID(Guid vid, int formatId)
        {
            if (formatId == 0)
            {
                return GetUrlFromVID(vid);
            }
            else
            {
                base.GetUrlFromVID(vid, formatId);
                string xmlResponse = ExtractSilverlightStreamingUrl(vid);
                return xmlResponse + "/" + vid + "_" + formatId.ToString() + ".wmv";
            }
        }
        
        public virtual void Delete(Guid vid)
        {
            //TODO
        }

        #endregion
    }
}
